package middleware

import (
	"fmt"
	"net/http"
	"strings"
	"time"
	"webook/internal/web"

	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
)

type LoginJwtMiddlewareBuilder struct {
	Paths []string
}

func NewLoginJwtMiddlewareBuilder() *LoginJwtMiddlewareBuilder {
	return &LoginJwtMiddlewareBuilder{}
}

func (b *LoginJwtMiddlewareBuilder) IgnorePaths(path string) *LoginJwtMiddlewareBuilder {
	b.Paths = append(b.Paths, path)
	return b
}

func (b *LoginJwtMiddlewareBuilder) Build() gin.HandlerFunc {
	//注意部分的请求不需要校验session
	return func(c *gin.Context) {
		// 检查白名单路径
		for _, path := range b.Paths {
			if c.Request.URL.Path == path {
				c.Next()
				return
			}
		}
		//用jwt来校验
		tokenHeader := c.GetHeader("Authorization")
		if tokenHeader == "" {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
				"code": 401,
				"msg":  "缺少Authorization头",
			})
			return
		}

		parts := strings.Split(tokenHeader, " ")
		if len(parts) != 2 || parts[0] != "Bearer" {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
				"code": 401,
				"msg":  "Authorization头格式错误，应为: Bearer <token>",
			})
			return
		}
		tokenStr := parts[1]
		claims := &web.UserClaims{}
		token, err := jwt.ParseWithClaims(tokenStr, claims, func(token *jwt.Token) (interface{}, error) {
			// 验证签名算法
			if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
				return nil, fmt.Errorf("无效的签名算法: %v", token.Header["alg"])
			}
			return []byte("1234567890"), nil
		})

		if err != nil {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
				"code": 401,
				"msg":  "JWT验证失败: " + err.Error(),
			})
			return
		}

		if !token.Valid {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
				"code": 401,
				"msg":  "JWT无效",
			})
			return
		}
		if claims.UserAgent != c.Request.UserAgent() {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
				"code": 401,
				"msg":  "用户代理不匹配",
			})
			return
		}
		now := time.Now()
		if claims.ExpiresAt.Sub(now) < time.Second*50 { //每十秒刷新一次
			tokenStr, err := token.SignedString([]byte("1234567890")) //使用密钥生成一个Token字符串
			if err != nil {
				c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
					"code": 401,
					"msg":  "JWT续签失败",
				})
				return
			}
			c.Header("x-jwt-token", tokenStr) //因为实际上更新了一个新的Token，要重新放到Header中
		}
		c.Set("userId", claims.UserId)
		c.Next()
	}
}
